package net.loyin.jfinal.ext;

import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.IDataSourceProvider;
import com.jfinal.plugin.activerecord.Model;
import net.loyin.annotation.TableBind;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by loyin on 16/1/12.
 */
public class AutoTableBindPlugin extends ActiveRecordPlugin{

    protected final Logger log = Logger.getLogger(getClass());
    /**
     * 需要扫描的父类
     */
    public Class<?> modelClass = Model.class;

    private List<Class<? extends Model>> excludeClasses = new ArrayList<Class<? extends Model>>();
    private List<String> includeJars = new ArrayList<String>();
    private boolean autoScan = true;
    private boolean includeAllJarsInLib = false;
    private List<String> scanPackages = new ArrayList<String>();
    /**对应的数据源*/
    private String dataSource;

    public AutoTableBindPlugin(IDataSourceProvider dataSourceProvider) {
        super(DbKit.MAIN_CONFIG_NAME, dataSourceProvider);
        dataSource=DbKit.MAIN_CONFIG_NAME;
    }

    /**
     * @param dataSource 数据源名称
     * @param dataSourceProvider
     */
    public AutoTableBindPlugin(String dataSource,IDataSourceProvider dataSourceProvider) {
        super(dataSource,dataSourceProvider);
        this.dataSource=dataSource;
    }
    /**
     * 添加需要扫描的包，默认为扫描所有包
     *
     * @param packages
     * @return
     */
    public AutoTableBindPlugin addScanPackages(String... packages) {
        for (String pkg : packages) {
            scanPackages.add(pkg);
        }
        return this;
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public AutoTableBindPlugin addExcludeClasses(Class<? extends Model>... clazzes) {
        for (Class<? extends Model> clazz : clazzes) {
            excludeClasses.add(clazz);
        }
        return this;
    }

    @SuppressWarnings("rawtypes")
    public AutoTableBindPlugin addExcludeClasses(List<Class<? extends Model>> clazzes) {
        if (clazzes != null) {
            excludeClasses.addAll(clazzes);
        }
        return this;
    }

    public AutoTableBindPlugin addJars(List<String> jars) {
        if (jars != null) {
            includeJars.addAll(jars);
        }
        return this;
    }

    public AutoTableBindPlugin addJars(String... jars) {
        if (jars != null) {
            for (String jar : jars) {
                includeJars.add(jar);
            }
        }
        return this;
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    public boolean start() {
        List<Class<?>> modelClasses = MyClassSearcher.of(modelClass).scanPackages(scanPackages).search();//.injars(includeJars).includeAllJarsInLib(includeAllJarsInLib).search();
        TableBind tb;
        for (Class modelClass : modelClasses) {
            if (excludeClasses.contains(modelClass)) {
                continue;
            }
            tb = (TableBind) modelClass.getAnnotation(TableBind.class);
            String tableName;
            if (tb != null) {
                String tbDataSource = tb.dataSource();
                if(dataSource.equals(tbDataSource)) {
                    tableName = tb.tableName();
                    if (StrKit.notBlank(tb.primaryKey())) {
                        this.addMapping(tableName, tb.primaryKey(), modelClass);
                        log.debug(dataSource + " addMapping(" + tableName + ", " + tb.primaryKey() + "," + modelClass.getName() + ")");
                    } else {
                        this.addMapping(tableName, modelClass);
                        log.debug(dataSource + " addMapping(" + tableName + ", " + modelClass.getName() + ")");
                    }
                }
            }
        }
        return super.start();
    }

    @Override
    public boolean stop() {
        return super.stop();
    }

    public AutoTableBindPlugin autoScan(boolean autoScan) {
        this.autoScan = autoScan;
        return this;
    }

    public AutoTableBindPlugin includeAllJarsInLib(boolean includeAllJarsInLib) {
        this.includeAllJarsInLib = includeAllJarsInLib;
        return this;
    }
}
